/**
 *
 */
package edu.tjut.tjutcommunity.recommend.algorithms;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import edu.tjut.tjutcommunity.entity.Post;
import edu.tjut.tjutcommunity.entity.Postlogs;
import edu.tjut.tjutcommunity.entity.Recommendations;
import edu.tjut.tjutcommunity.entity.User;
import edu.tjut.tjutcommunity.mapper.PostlogsMapper;
import edu.tjut.tjutcommunity.mapper.RecommendationsMapper;
import edu.tjut.tjutcommunity.recommend.contentbasedrecommend.CustomizedHashMap;
import edu.tjut.tjutcommunity.service.PostService;
import edu.tjut.tjutcommunity.service.UserService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;


@Component
public class RecommendKit {

    public static final Logger logger = Logger.getLogger(RecommendKit.class);

    /**
     * 推荐帖子的时效性天数，即从推荐当天开始到之前beforeDays天的帖子属于仍具有时效性的帖子，予以推荐。
     */
    @Value("${recommend.beforeDays}")
    public void setBeforeDays(int b) {
        beforeDays = b;
    }
    private static int beforeDays;

    @Value("${recommend.activeDays}")
    public void setActiveDays(int a) {
        activeDays = a;
    }

    private static int activeDays;

    static PostService postService= null;

    static UserService userService = null;

    static PostlogsMapper postlogsMapper= null;

    static RecommendationsMapper recommendationsMapper= null;

    public RecommendKit(PostService postService, UserService userService, PostlogsMapper postlogsMapper, RecommendationsMapper recommendationsMapper) {
        this.postService = postService;
        this.userService = userService;
        this.postlogsMapper = postlogsMapper;
        this.recommendationsMapper = recommendationsMapper;
    }

    /**
     * @return the inRecDate 返回时效时间的"year-month-day"的格式表示，方便数据库的查询
     */

    public static String getInRecDate() {
        return getSpecificDayFormat(beforeDays);
    }

    /**
     * @return the inRecDate 返回时效时间的"year-month-day"的格式表示，方便数据库的查询
     */
    public static String getInRecDate(int beforeDays) {
        return getSpecificDayFormat(beforeDays);
    }

    /**
     * @return the inRecDate 返回时效时间timestamp形式表示，方便其他推荐方法在比较时间先后时调用
     */
    public static Timestamp getInRecTimestamp(int before_Days) {
        Calendar calendar = Calendar.getInstance(); // 得到日历
        calendar.add(Calendar.DAY_OF_MONTH, before_Days); // 设置为前beforeNum天
        return new Timestamp(calendar.getTime().getTime());
    }

    /**
     * 过滤方法filterOutDateNews() 过滤掉失去时效性的新闻（由beforeDays属性控制）
     */
    public static void filterOutDatePosts(Collection<Integer> col) {
        try {
            List<Post> postsList = postService.getPostByIds((Set<Integer>) col);
            for (Post post : postsList) {
                if (post.getUpdateTime().before(getInRecTimestamp(beforeDays))) {
                    col.remove(post.getPid());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * filterBrowsedPosts() 过滤掉已经用户已经看过的帖子
     */
    public static void filterBrowsedPosts(Collection<Integer> col, Integer userId) {
        try {
            QueryWrapper<Postlogs> qw = new QueryWrapper<>();
            qw.eq("uid", userId);
            List<Postlogs> postlogsList = postlogsMapper.selectList(qw);
            for (Postlogs postlogs : postlogsList) {
                col.remove(postlogs.getLid());
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * filterReccedPosts() 过滤掉已经推荐过的忒子（在recommend表中查找）
     */
    public static void filterReccedPosts(Collection<Integer> col, Integer userId) {
        try {
            //但凡近期已经给用户推荐过的新闻，都过滤掉
            String inRecDate = getInRecDate();
            QueryWrapper<Recommendations> qw = new QueryWrapper<>();
            qw.eq("uid", userId);
            qw.gt("create_time", inRecDate);
            qw.eq("has_recommend", 0);
            List<Recommendations> recommendationList = recommendationsMapper.selectList(qw);

            for (Recommendations recommendation : recommendationList) {
                col.remove(recommendation.getPid());
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static HashMap<Integer, CustomizedHashMap<Integer, CustomizedHashMap<String, Double>>> getUserPrefListMap(
            Collection<Integer> userSet) {
        HashMap<Integer, CustomizedHashMap<Integer, CustomizedHashMap<String, Double>>> userPrefListMap = null;
        try {
            List<User> users = userService.getUsers(userSet);
            //最外层是用户id，该map存储所有用户的喜好列表
            userPrefListMap = new HashMap<Integer, CustomizedHashMap<Integer, CustomizedHashMap<String, Double>>>();
            for (User user : users) {
                userPrefListMap.put(user.getUid(), JsonKit.jsonPrefList2Map(user.getPrefList()));
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return userPrefListMap;
    }

    /**
     * 获取所有用户的Id列表
     *
     * @return
     */
    public static ArrayList<Integer> getUserList() {
        ArrayList<Integer> users = new ArrayList<Integer>();
        try {
            List<User> userList = userService.getUsers();
            for (User user : userList) {
                users.add(user.getUid());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return users;
    }

    public int getbeforeDays() {
        return beforeDays;
    }


    public static String getSpecificDayFormat(int before_Days) {
        SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance(); // 得到日历
        calendar.add(Calendar.DAY_OF_MONTH, before_Days); // 设置为前beforeNum天
        Date d = calendar.getTime();
        return date_format.format(d);
    }




    /**
     * 将推荐结果插入recommend表
     *
     * @param userId
     *            推荐目标用户id
     * @param postsIte
     *            待推荐帖子集合的迭代器
     * @param recAlgo
     *            标明推荐结果来自哪个推荐算法(RecommendAlgorithm.XX)
     */
    public static void insertRecommend(Integer userId, Iterator<Integer> postsIte, int recAlgo) {
        try {
            while (postsIte.hasNext()) {
                Recommendations rec = new Recommendations();
                rec.setUid(userId);
                rec.setDeriveAlgorithm(recAlgo);
                rec.setPid(postsIte.next());
                recommendationsMapper.insert(rec);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *  Acquire a list of active users
     * "Active" means who read news recently ('recent' determined by method getInRecDate(), default in a month)
     *
     * @return
     */
    public static List<Integer> getActiveUsers() {
        try {
//            List<Users> userList = Users.dao.find("select distinct id,name from users where latest_log_time>" + getInRecDate(activeDays));
            String activeDay = getInRecDate(activeDays);
            List<User> userList = userService.getUsers(activeDay);
            List<Integer> userIDList = new ArrayList<Integer>();
            for (User user : userList)
                userIDList.add(user.getUid());
            return userIDList;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        logger.info("获取活跃用户异常！");
        return null;
    }

    public static List<Integer> getAllUsers() {
        try {
//            List<User> userList = Users.dao.find("select distinct id,name from users");
            List<User> userList = userService.getUsers();
            List<Integer> userIDList = new ArrayList<Integer>();
            for (User user : userList)
                userIDList.add(user.getUid());
            return userIDList;
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("获取全体用户异常！");
        return null;
    }


    /**
     * 去除数量上超过为算法设置的推荐结果上限值的推荐结果
     *
     * @param set
     * @param N
     * @return
     */
    public static void removeOverPosts(Set<Integer> set, int N) {
        int i = 0;
        Iterator<Integer> ite = set.iterator();
        while (ite.hasNext()) {
            if (i >= N) {
                ite.remove();
                ite.next();
            } else {
                ite.next();
            }
            i++;
        }
    }
}
